<?php

/**
 * @Author: RainLee <rainlee1990@yeah.net>
 * @Date: 2022-01-10 22:38:52
 * @LastEditors: RainLee <rainlee1990@yeah.net>
 * @LastEditTime: 2022-03-29 20:49:35
 * @Description: 文件说明
 */

namespace rainlee\auth\guard;

use rainlee\auth\provider\CreateUserProviders;
use rainlee\auth\Authenticatable;
use rainlee\auth\jwt\JwtManager;
use rainlee\auth\Policies;
use think\facade\Request;

class JwtGuard
{
    use CreateUserProviders;

    protected $provider = null;

    protected $policies = null;

    protected $ignored = [];

    protected $guardName;

    protected $jwt;

    protected $payload = [];

    protected $user = null;

    protected $recallAttempted = false;


    public function __construct($name, $config)
    {
        $this->guardName = $name;
        $this->ignored = $config['ignored'] ?? [];
        $this->payload = $config['payload'];
        $this->policies = $config['policies'] ?? null;
        $this->jwt = (new JwtManager())->guard($name);
        $this->provider = $this->createUserProviders($config['provider']);
    }

    /**
     * 尝试登录
     *
     * @param  array  $credentials
     * @param  bool   $remember
     * @return bool
     */
    public function attempt(array $credentials = [], $remember = false)
    {
        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
        if (!is_null($user) && $this->hasValidCredentials($user, $credentials)) {
            return $this->login($user);
        }

        return false;
    }

    /**
     * 尝试通过ID登录
     * 
     * @param int $id
     * @param bool $remember
     * @return bool
     */
    public function attemptById($id, $remember = false)
    {
        if (!is_null($user = $this->provider->retrieveById($id))) {
            return $this->login($user);
        }
        return false;
    }

    /**
     * 验证参数有效性
     * 
     * @param \rainlee\auth\Authenticatable|null $user 用户对象
     * @param array $credentials 参数
     * @return bool
     */
    protected function hasValidCredentials($user, $credentials)
    {
        return !is_null($user) && $this->provider->validatePassword($user, $credentials['password']);
    }

    /**
     * 登录操作
     * 
     * @param \rainlee\auth\Authenticatable $user 用户对象
     * @param bool $remember
     * @return void
     */
    protected function login(Authenticatable $user)
    {
        $token = $this->createToken($user);
        $this->setUser($user);
        return $token;
    }

    /**
     * 创建Token
     * 
     * @return string
     */
    protected function createToken(Authenticatable $user)
    {
        $claims = [];
        foreach ($this->payload as $value) {
            $claims[$value] = $user->$value;
        }
        return $this->jwt->build($claims);
    }

    /**
     * 获取用户信息
     * 
     * @return \rainlee\auth\Authenticatable|null
     */
    public function user()
    {
        // 用户存在则只接返回用户信息
        if (!is_null($this->user)) {
            return $this->user;
        }

        if (!$this->jwt->validation()) {
            return null;
        }

        $id = $this->jwt->getId();
        if (!is_null($id)) {
            $this->user = $this->provider->retrieveById($id);
        }

        return $this->user;
    }

    /**
     * 验证用户是否登录
     *
     * @return bool
     */
    public function check()
    {
        return !is_null($this->user());
    }

    /**
     * 权限认证
     *
     * @return \rainlee\auth\Policies
     */
    public function authorization()
    {
        if (is_null($this->policies)) {
            return;
        }
        return new Policies($this->policies, $this->user());
    }

    /**
     * 判断是否为无需认证的节点
     */
    public function isIgnoredNode($node)
    {
        if (in_array($node, $this->ignored)) {
            return true;
        }
        return false;
    }

    /**
     * 设置当前用户
     * 
     * @param \rainlee\auth\Authenticatable $user
     * @return void
     */
    protected function setUser(Authenticatable $user)
    {
        $this->user = $user;
    }
}
